<?php

require_once 'classes/database.php';
require_once 'classes/albums.php';

class Photo{
	public $id, $owner, $albumid, $original_file_name, $width, $height, $file_name, $text, $date_taken, $date_gps, $date_uploaded, $latitude, $longitude, $latitudeDecimal, $longitudeDecimal;

	static $dbTableName = "pg_photo";
	static $dbTableNameGeoAlbuns = "pg_geoalbum_photo";
	static $dbGeomSRID = "4326";
	static $dbSelectAtt = " *, X(geom) AS longitude, Y(geom) as latitude ";

	function __construct($idN,$ownerN, $albumidN, $file_nameN, $date_uploadedN){
		$this->id = $idN;
		$this->owner = $ownerN;
		$this->albumid = $albumidN;
		$this->file_name = $file_nameN;
		$this->date_uploaded = $date_uploadedN;
	}
	
	function setWidth($new){
		$this->width = $new;
	}
	function setHeight($new){
		$this->height = $new;
	}

	function setAlbumid($new){
		$this->albumid = $new;
	}

	function setOwner($new){
		$this->owner = $new;
	}

	function setOriginal_file_name($new){
		$this->original_file_name = $new;
	}
	
	function setFile_name($new){
		$this->file_name = $new;
	}
	
	function setText($new){
		$this->text = $new;
	}
	
	function setDate_taken($new){
		$this->date_taken = $new;
	}
	
	function setDate_gps($new){
		$this->date_gps = $new;
	}
	
	function setDate_uploaded($new){
		$this->date_uploaded = $new;
	}
	
	function setLatitude($new){
		$this->latitude = $new;
	}
	
	function setLongitude($new){
		$this->longitude = $new;
	}
	
	function setLatitudeDecimal($new){
		$this->latitudeDecimal = $new;
	}
	
	function setLongitudeDecimal($new){
		$this->longitudeDecimal = $new;
	}

	function getId(){
		return($this->id);
	}
	
	function getWidth(){
		return($this->width);
	}
	function getHeight(){
		return($this->height);
	}

	function getOwner(){
		return($this->owner);
	}

	function getAlbumid(){
		return($this->albumid);
	}

	function getOriginal_file_name(){
		return($this->original_file_name);
	}
	
	function getFile_name(){
		return($this->file_name);
	}
	
	function getText(){
		return($this->text);
	}
	
	function getLatitude(){
		return($this->latitude);
	}
	
	function getLongitude(){
		return($this->longitude);
	}
	
	function getLatitudeDecimal(){
		return($this->latitudeDecimal);
	}
	
	function getLongitudeDecimal(){
		return($this->longitudeDecimal);
	}
	
	function getLongitudeExpression(){
		return($this->getCoordExpression($this->longitude));
	}
	
	function getLatitudeExpression(){
		return($this->getCoordExpression($this->latitude));
	}
	
	private function getCoordExpression($coord){
		list($coordRef,$degrees,$minutes,$seconds) = split(':',$coord);
		return("($coordRef*($degrees+($minutes/60)+($seconds/3600)))");
	}
	
	function getDate_taken(){
		if(is_null($this->date_taken)){
			return($this->getDate_uploaded());
		}else{
			return($this->date_taken);
		}
	}
	
	function getDate_gps(){
		return($this->date_gps);
	}
	
	function getDate_uploaded(){
		return($this->date_uploaded);
	}
	
	function getGeomWKT(){
		$concat = "";
		$latDec = $this->getLatitudeDecimal();
		$longDec = $this->getLongitudeDecimal();
		if(is_null($latDec) || empty($latDec) || empty($longDec) || is_null($longDec)){
			$lonExp = $this->getLongitudeExpression();
			$latExp = $this->getLatitudeExpression();
			$concat="CONCAT('POINT(',$lonExp,' ',$latExp,')')";
		}else{
			$concat="'POINT({$longDec} {$latDec})'";
		}
		return("GeomFromText($concat,".Photo::$dbGeomSRID.")");
	}
	
	function getURL(){
		return("./photos/". $this->getOwner() ."/".$this->getFile_name());
	}
	
	function copyData($photo){
		$text = $photo->getText();
		if(!is_null($text) && !empty($text))
			$this->setText($text);
		
		$albumid = $photo->getAlbumid();
		if(!is_null($albumid) && !empty($albumid))
			$this->setAlbumid($albumid);
		
		$lat = $photo->getLatitudeDecimal();
		$lng = $photo->getLongitudeDecimal();
		
		if(!is_null($lat) && !empty($lat) && !is_null($lng) && !empty($lng)){
			$this->setLatitudeDecimal($lat);
			$this->setLongitudeDecimal($lng);
		}
	}
	
}

class PhotoDBUtils{
	private $dbUtils;

	function __construct(){
		$this->dbUtils = new DatabaseUtils();
	}

	function __destruct(){
		unset($database);
	}

	function photoFromRow($row){
		if(
				isset($row["owner"]) && isset($row["id"]) && isset($row["original_file_name"])
				&& !(trim($row["original_file_name"])==='') && !(trim($row["id"])==='') && !(trim($row["owner"])==='')
		){
			
			$p = new Photo($row["id"],$row["owner"],$row["albumid"],$row["file_name"],$row["date_uploaded"]);
			$p->setText($row["text"]);
			$p->setDate_taken($row["date_taken"]);
			$p->setDate_gps($row["date_gps"]);
			$p->setLatitudeDecimal($row["latitude"]);
			$p->setLongitudeDecimal($row["longitude"]);
			$p->setAlbumid($row["albumid"]);
			$p->setWidth($row["width"]);
			$p->setHeight($row["height"]);
			$p->setOriginal_file_name($row["original_file_name"]);
			return($p);
		}else{
			return(NULL);
		}
	}
	
	function findUserGeoPhotos($owner,$limit){
		$q = "SELECT p.".Photo::$dbSelectAtt.", ga_p.geoalbumid as gaid FROM ".Photo::$dbTableName." p, ".Photo::$dbTableNameGeoAlbuns." ga_p WHERE ga_p.photoid = p.id AND p.owner=:owner ";
		$params = array(":owner"=>$owner);
		if($limit>0){
			$q = $q." LIMIT 0,:limit";
			$params[":limit"] = $limit;
		}
		$result = $this->dbUtils->runSelect($q, $params);
		if(count($result)<1){
			return(array("status"=>FALSE,"message"=>"No photo found."));
		}else{
			return(array("status"=>TRUE,"message"=>"Photos found.", "photos"=>$result));
		}
	}

	function findUserPhotos($owner, $albumid, $limit){
		$q = "SELECT ".Photo::$dbSelectAtt." FROM ".Photo::$dbTableName." WHERE owner = :owner ";
		$params =  array(":owner"=>$owner);
		if(!is_null($albumid) && !empty($albumid) && $albumid>=0){
			$q = $q." AND albumid=:albumid ";
			$params[":albumid"] = $albumid;
		}
		if($limit>0){
			$q = $q." LIMIT 0,:limit";
			$params[":limit"] = $limit;
		}
		$result = $this->dbUtils->runSelect($q, $params);
		if(count($result)<1){
			return(array("status"=>FALSE,"message"=>"No photo found."));
		}else{
			return(array("status"=>TRUE,"message"=>"Photos found.", "photos"=>$result));
		}
	}
	
	function findPhotoById($idN,$ownerN){
		$q = "SELECT p.".Photo::$dbSelectAtt.",a.label,a.cover FROM ".Photo::$dbTableName." p, ".Album::$dbTableName." a WHERE a.id=p.albumid AND p.id = :id AND p.owner = :owner";
		$params =  array(":id"=>$idN, ":owner"=>$ownerN);
		$result = $this->dbUtils->runSelect($q, $params);
		
		if(count($result)<1){
			return(array("status"=>FALSE,"message"=>"No photo found."));
		}else{
			return(array("status"=>TRUE,"message"=>"Photo found.", "photo"=>$result[0]));
		}
	}
	
	function savePhotoInGeoAlbuns($ids,$geoAlbuns){
		$values = "";
		$idsStr = "";
		$sep = "";
		$sepVals = "";
		foreach($ids as $pid){
			if(is_numeric($pid)){
				$idsStr = $sep.$pid;
				foreach($geoAlbuns as $a){
					$values = "(".$a["id"].",".$pid.")".$sepVals.$values;
					$sepVals = ",";
				}
				$sep = ",";
			}
		}
		
		
		if(!empty($values) && !empty($idsStr)){
			$q = "DELETE FROM ".Photo::$dbTableNameGeoAlbuns." WHERE photoid in (".$idsStr.")";
			$params = array();
			$this->dbUtils->runDelete($q, $params);
			
			$q = "INSERT INTO ".Photo::$dbTableNameGeoAlbuns."(geoalbumid, photoid) VALUES ".$values;
			$resultSave = $this->dbUtils->runInsert($q, $params);
			
			if($resultSave>0){
				return(array("status"=>TRUE, "message"=>"Saved."));
			}else{
				return(array("status"=>FALSE, "message"=>("Couldn't save relations.")));
			}
		}
	}

	function savePhoto($p){
		$idP = $p->getId();
		$result = array();
		if(!isset($idP) || is_null($idP)){
			$q = "SELECT * FROM ".Photo::$dbTableName." WHERE file_name = :file_name AND owner = :owner";
			$params = array(":file_name"=>$p->getFile_name(), ":owner"=>$p->getOwner());
			$result = $this->dbUtils->runSelect($q, $params);
		}else{
			$q = "SELECT * FROM ".Photo::$dbTableName." WHERE id = :id AND owner = :owner";
			$params = array(":id"=>$idP, ":owner"=>$p->getOwner());
			$result = $this->dbUtils->runSelect($q, $params);
		}
		
	
		if(count($result)<1){
			$pGeom = "";
			$pGeomDef = "";
			$params = array(":owner"=>$p->getOwner(),
					":albumid"=>$p->getAlbumid(),
					":width"=>$p->getWidth(),
					":height"=>$p->getHeight(),
					":original_file_name"=>$p->getOriginal_file_name(),
					":file_name"=>$p->getFile_name(),
					":text"=>$p->getText(),
					":date_taken"=>$p->getDate_taken(),
					":date_gps"=>$p->getDate_gps(),
					":date_uploaded"=>$p->getDate_uploaded());
			$pGeomLat = $p->getLatitude();
			$pGeomLon = $p->getLongitude();
			if(!is_null($pGeomLat) && !is_null($pGeomLon)){
				$pGeom = ", ".$p->getGeomWKT();
				$pGeomDef = ", geom";
			}
			
			$q = "INSERT INTO ".Photo::$dbTableName."(owner,albumid,width,height,original_file_name,file_name,text,date_taken,date_gps, date_uploaded".$pGeomDef.") VALUES(:owner, :albumid, :width, :height, :original_file_name, :file_name, :text, :date_taken, :date_gps, :date_uploaded".$pGeom.")";
				
			$resultSave = $this->dbUtils->runInsert($q, $params);
			if(!isset($idP) || is_null($idP)){
				
			}
			$q = "SELECT p.".Photo::$dbSelectAtt.",a.label,a.cover FROM ".Photo::$dbTableName." p, ".Album::$dbTableName." a WHERE a.id=p.albumid AND p.file_name = :file_name AND p.owner = :owner";
			$params = array(":file_name"=>$p->getFile_name(), ":owner"=>$p->getOwner());
			$result = $this->dbUtils->runSelect($q, $params);
			
			foreach ($result as $photo){
				$p = $this->photoFromRow($photo);
			}
				
		}else{
			foreach ($result as $photoRow){
				$photo = $this->photoFromRow($photoRow);
				$photo->copyData($p);
				$params = array(":id"=>$photo->getId(),
					":albumid"=>$photo->getAlbumid(),
					":text"=>$photo->getText());
				$pGeomLat = $photo->getLatitude();
				$pGeomLon = $photo->getLongitude();
				
				$pGeomLatDec = $photo->getLatitudeDecimal();
				$pGeomLonDec = $photo->getLongitudeDecimal();
				if((!is_null($pGeomLat) && !is_null($pGeomLon))
					|| (!is_null($pGeomLatDec) && !is_null($pGeomLonDec))	){
					$pUpdateGeom = ", geom=".$photo->getGeomWKT();
				}
				
				$q = "UPDATE ".Photo::$dbTableName." SET albumid=:albumid, text=:text ".$pUpdateGeom." WHERE id=:id";
				$resultSave = $this->dbUtils->runUpdate($q, $params);
				$p->copyData($photo);
			}
		}
		if($resultSave>0){
			return(array("status"=>TRUE, "message"=>"Saved.", "photo"=>$p));
		}else{
			return(array("status"=>FALSE, "photo"=>$p, "message"=>("Couldn't save photo: ".$p->getOriginal_file_name())));
		}
	}
}

class PhotoUtils{
	
	function __construct(){
		ini_set('memory_limit', '128M');
	}
	
	function createThumbnail($imgpath, $fname){
		if (!file_exists($imgpath . 'thumbs')) {
			mkdir($imgpath . 'thumbs');
		}
		$strArr = explode(".", $fname);
		$mime_type = strtolower($strArr[count($strArr)-1]);
		$img = NULL;
		$path = "{$imgpath}{$fname}";
		switch ($mime_type){
			case "jpeg":
				// Get image from file
				$img = imagecreatefromjpeg($path);
				break;
			case "jpg":
				// Get image from file
				$img = imagecreatefromjpeg($path);
				break;
			case "png":
				// Get image from file
				$img = imagecreatefrompng($path);
				break;
			case "gif":
				// Get image from file
				$img = imagecreatefromgif($path);
				break;
		}
		
		if(!is_null($img)){
			$width = imagesx( $img );
			$height = imagesy( $img );
			$thumbDimensions = 300;
			if($width>$height){
				$new_height = $thumbDimensions;
				$new_width = floor( $width * ( $thumbDimensions / $height ) );
			}else{
				$new_width = $thumbDimensions;
				$new_height = floor( $height * ( $thumbDimensions / $width ) );
			}
				
			$tmp_img = imagecreatetruecolor( $new_width, $new_height );
				
			// copy and resize old image into new image
			imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
				
			// save thumbnail into a file
			imagejpeg( $tmp_img, "{$imgpath}thumbs/{$fname}" );
		}
	}
}

class ExifUtils{
	
	private $exif;
	
	function __construct($exifN){
		$this->exif = $exifN;
	}
	
	private function processStringDivisions($strDiv){
		list($num,$div) = split('/',$strDiv);
		return(is_numeric(doubleval($div))?bcdiv($num,$div):$num);
	}
	
	private function processGPSRef($strRef){
		if($strRef=='W' || $strRef=='S')
			return('-1');
		else
			return('1');
	}
	
	private function getGPSCoordinate($coordName){
		if(!is_null($this->exif["GPS"])){
			$coordRef = $this->exif["GPS"]["GPS".$coordName."Ref"];
			$coordExif = $this->exif["GPS"]["GPS".$coordName];
			
			$degrees = $coordExif[0];
			$minutes = $coordExif[1];   //Transform into degrees
			$seconds = $coordExif[2]; //Transform into degrees
			
			return($this->processGPSRef($coordRef).":(".$degrees."):(".$minutes."):(".$seconds.")");
		}else{
			return(NULL);
		}
	}
	
	function getCoordinateLatitude(){
		return($this->getGPSCoordinate('Latitude'));
	}
	
	function getCoordinateLongitude(){
		return($this->getGPSCoordinate('Longitude'));
	}
	
	function getGPSDateTime(){
		$gpsExif = $this->exif["GPS"];
		if(!is_null($gpsExif)){
			$date = $gpsExif["GPSDateStamp"];
			$timeExif = $gpsExif["GPSTimeStamp"];
			
			if(!is_null($date) && !is_null($timeExif)){
				$date = str_replace(':','-',$date);
				$hours = intval($this->processStringDivisions($timeExif[0]));
				$minutes = intval($this->processStringDivisions($timeExif[1]));
				$seconds = intval($this->processStringDivisions($timeExif[2]));
				
				$dateTimeGPS = $date." ".$hours.":".$minutes.":".$seconds;
				return($dateTimeGPS);
			}
		}
		return(NULL);
	}
	
	function getEXIFDateTime(){
		$tagExif = $this->exif["EXIF"];
		if(!is_null($tagExif)){
			$dateExif = $tagExif["DateTimeOriginal"];
			if(!is_null($dateExif)){
				$date = preg_replace('/:/','-',$dateExif,2);
				return($date);
			}
		}
		return(NULL);
	}
}

$photoUtils = new PhotoDBUtils();